﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.ServiceProcess;
using System.Diagnostics;
using TipokHostManager.Model;
using TipokHostContract;

namespace TipokHostManager.WMIManager
{
    public class ManagementBase<T> : ManagementSingle<T> where T : ManagementBase<T>, new()
    {
        #region fields
        private string host;
        private string username;
        private string password;
        protected ManagementClass managementClass;
        protected string managementPath;
        protected ManagementScope managementScope;
        protected EnumWMICalassName className;
        #endregion

        #region Properties
        public string Host
        {
            get { return host; }
        }
        #endregion

        public ManagementBase()
        {
            ManagementBaseInit(EnumWMICalassName.Win32_Service, ".", string.Empty, string.Empty);
        }

        public void ManagementBaseInit(EnumWMICalassName classname, string host, string username, string password)
        {
            this.className = classname;
            this.host = host;
            this.username = username;
            this.password = password;
            this.managementPath = string.Format("\\\\{0}\\root\\cimv2:{1}", host, classname);
            this.managementClass = new ManagementClass(managementPath);
            if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
            {
                ConnectionOptions connectionOptions = new ConnectionOptions()
                {
                    Username = username,
                    Password = password
                };
                this.managementScope = new ManagementScope(managementPath, connectionOptions);
                this.managementClass.Scope = this.managementScope;
            }
        }

        /// <summary>
        /// 设置ManagementScope.Path的搜索类名 
        /// </summary>
        protected void SetPathClassName(EnumWMICalassName className)
        {
            this.managementPath = string.Format("\\\\{0}\\root\\cimv2:{1}", host, className);
            this.managementClass.Scope.Path = new ManagementPath(this.managementPath);
        }


        #region VerifyConnection
        /// <summary>
        /// Verify Remote machine 
        /// </summary>
        /// <returns></returns>
        public bool VerifyConnection()
        {
            bool flag = true;
            try
            {
                if (this.managementScope != null)
                {
                    this.managementScope.Connect();
                }
            }
            catch
            {
                flag = false;
            }

            return flag;
        }
        #endregion

        #region Helper

        protected ReturnValue InvokeProcess(string workerPath, string command)
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.WorkingDirectory = workerPath;
            p.StartInfo.CreateNoWindow = false;
            if (!workerPath.EndsWith(@"\"))
            {
                workerPath += @"\";
            }
            string batCommandSrc = workerPath + command + ".bat";
            if (!System.IO.File.Exists(batCommandSrc))
            { 
                //write log
                System.Console.WriteLine("InvokeProcess Failure, Not find file path:" + batCommandSrc);
                return ReturnValue.UnknownFailure;
            }
            System.IO.StreamReader strm = System.IO.File.OpenText(batCommandSrc);
            p.OutputDataReceived += new DataReceivedEventHandler(ProcessOutputDataRecived);
            p.ErrorDataReceived += new DataReceivedEventHandler(ProcessErrDateReceiver);
            p.Start();
            p.BeginErrorReadLine();
            System.IO.StreamWriter sIn = p.StandardInput;
            while (strm.Peek() != -1)
            {
                sIn.WriteLine(strm.ReadLine());
            }
            strm.Close();
            //p.WaitForExit(60000);
            sIn.Close();
            sIn = null;
            p.Close();
            p.Dispose();
            p = null;
            return ReturnValue.Success;
        }

        private void ProcessOutputDataRecived(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (!String.IsNullOrEmpty(outLine.Data))
            {
                // Add the text to the collected output. 
                System.Console.WriteLine("Info, ProcessOutputDataRecived Data:" + outLine.Data);
            }
        }

        private void ProcessErrDateReceiver(object sender, DataReceivedEventArgs e)
        {
            System.Console.WriteLine("Failure, ProcessErrDateReceiver Data:" + e.Data);
        }

        protected ReturnValue InvokeMethod(string serviceName, string commandName)
        {
            return InvokeMethod(this.className, serviceName, commandName);
        }

        protected ReturnValue InvokeMethod(EnumWMICalassName className, string serviceName, string commandName)
        {
            this.SetPathClassName(className);
            var path = new ManagementPath(string.Concat(this.managementPath, string.Format(".Name=\"{0}\"", serviceName)));
            using (ManagementObject service = this.managementClass.CreateInstance())
            {
                try
                {
                    service.Path = path;
                    ManagementBaseObject outParams = service.InvokeMethod(commandName, null, null);
                    return (ReturnValue)Enum.Parse(typeof(ReturnValue), outParams["ReturnValue"].ToString());
                }
                catch (Exception ex)
                {
                    if (ex.Message.ToLower().Trim() == "not found" || ex.GetHashCode() == 41149443)
                    {
                        //not find service nothing to do
                    }
                    else
                    {
                        throw ex;
                    }
                }
            }

            return ReturnValue.UnknownFailure;
        }

        protected ServiceModel ExtractServiceItem(ManagementObject mo)
        {
            return new ServiceModel()
            {
                Description = Convert.ToString(mo["Description"]),
                DisplayName = Convert.ToString(mo["DisplayName"].ToString()),
                ServiceName = Convert.ToString(mo["Name"]),
                PathName = Convert.ToString(mo["PathName"]),
                ProcessId = Convert.ToInt32(mo["ProcessId"]),
                StartMode = Convert.ToString(mo["StartMode"]),
                StartName = Convert.ToString(mo["StartName"]),
                State = GetServiceControllerStatus(Convert.ToString(mo["State"])),
                MachineName = Convert.ToString(mo["SystemName"])
            };
        }

        private ServiceControllerStatus GetServiceControllerStatus(string _state)
        {
            ServiceControllerStatus toReturn = ServiceControllerStatus.Stopped;
            switch (_state)
            {
                case "Running":
                    toReturn = ServiceControllerStatus.Running;
                    break;
                case "Stopped":
                    toReturn = ServiceControllerStatus.Stopped;
                    break;
                case "Paused":
                    toReturn = ServiceControllerStatus.Paused;
                    break;
                case "Start Pending":
                    toReturn = ServiceControllerStatus.StartPending;
                    break;
                case "Stop Pending":
                    toReturn = ServiceControllerStatus.StopPending;
                    break;
                case "Continue Pending":
                    toReturn = ServiceControllerStatus.ContinuePending;
                    break;
                case "Pause Pending":
                    toReturn = ServiceControllerStatus.PausePending;
                    break;
            }
            return toReturn;

        }
        #endregion
    }
}
